﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
using MVVM.Core;

namespace ObjectModel.Excel
{
    public enum LookUpBy { Row, Col, Both };

	public enum SearchDirection {
		Previous,
		Next,
	};

    public class LookUpStep : NotificationBase
    {
        #region Fields

        private LookUpBy mLookUpSetting = LookUpBy.Row;
    	private SearchDirection mSearchDirection = SearchDirection.Next;
        private string mlookUpString = string.Empty;
        private int mColAbs;
        private int mColRelOffset;
        private int mRowAbs;
        private int mRowRelOffset;

        #endregion

        #region Properties

    	public SearchDirection SearchDirection 
		{ 
			get { return mSearchDirection; }
			set { mSearchDirection = value; } 
		}

        public LookUpBy LookUpSetting
        {
            get { return mLookUpSetting; }
            set
            {
				mLookUpSetting = value;
                OnPropertyChanged("LookUpSetting");
            }
        }

        public string LookUpString
        {
            get { return mlookUpString; }
            set 
            {
                mlookUpString = value;
                OnPropertyChanged("LookUpString");
            }
        }

        public int ColAbs
        {
            get { return mColAbs; }
            set
            {
				if(value > 0) {
					RowAbs = 0;
					ColRelOffset = 0;
					LookUpSetting = LookUpBy.Col;
				}
            	mColAbs = value;
                OnPropertyChanged("ColAbs");
            }
        }

        public int ColRelOffset
        {
            get { return mColRelOffset; } 
            set
            {
                mColRelOffset = value;
                ColAbs = 0;
                OnPropertyChanged("ColRelOffset");
            }
        }

        public int RowAbs
        {
            get { return mRowAbs; }
            set
            {
				if(value > 0) {
					ColAbs = 0;
					RowRelOffset = 0;
					LookUpSetting = LookUpBy.Row;
				}
				mRowAbs = value;
            	OnPropertyChanged("RowAbs");
            }
        }
        
        public int RowRelOffset 
        {
            get { return mRowRelOffset; }
            set
            {
                mRowRelOffset = value;
                RowAbs = 0;
                OnPropertyChanged("RowRelOffset");
            }
        }

        #endregion

        #region Methods

        public Range Resolve(Range startRange)
        {            
            if (startRange == null) return null;
            if (mlookUpString == string.Empty) throw new InvalidOperationException("Look-up string is empty");

            Range resolvedRange = null;
            Range lookUpRange = null;
            Application app = startRange.Application;
            Worksheet ws = startRange.Worksheet;
            int startRow;
            int startCol;

            switch (LookUpSetting)
            {    
                case LookUpBy.Row:
                    int lookUpRow = RowAbs != 0 ? RowAbs : startRange.Row + RowRelOffset;
                    startCol = startRange.Column + ColRelOffset;
                    if (lookUpRow > 0 && lookUpRow <= ws.Rows.Count && startCol > 0 && startCol <= ws.Columns.Count) {
						if(SearchDirection == SearchDirection.Next) {
							lookUpRange = ws.Range[ws.Cells[lookUpRow, startCol], ws.Cells[lookUpRow, ws.UsedRange.Columns.Count]];
						}
						else {
							lookUpRange = ws.Range[ws.Cells[lookUpRow, 1], ws.Cells[lookUpRow, startCol]];
						}
                    }
            		break;
            
                case LookUpBy.Col:
                    int lookUpCol = ColAbs != 0 ? ColAbs : startRange.Column + ColRelOffset;
                    startRow = startRange.Row + RowRelOffset;
                    if (lookUpCol > 0 && lookUpCol <= ws.Columns.Count && startRow > 0 && startRow <= ws.Rows.Count) {
                    	if(SearchDirection == SearchDirection.Next) {
                    		lookUpRange = ws.Range[ws.Cells[startRow, lookUpCol], ws.Cells[ws.UsedRange.Rows.Count, lookUpCol]];
                    	}
                    	else {
                    		lookUpRange = ws.Range[ws.Cells[1, lookUpCol], ws.Cells[startRow, lookUpCol]];
                    	}
                    }
            		break;

                default:
                    startRow = startRange.Row + RowRelOffset;
                    startCol = startRange.Column + ColRelOffset;
                    if (startRow > 0 && startRow <= ws.Rows.Count && startCol > 0 && startCol <= ws.Columns.Count) {
						// Implement search previous
						if(SearchDirection == SearchDirection.Next) {
							lookUpRange = ws.Range[ws.Cells[startRow, startCol], ws.Cells[ws.UsedRange.Rows.Count, ws.UsedRange.Columns.Count]];
						}
						else {
							lookUpRange = ws.Range[ws.Cells[1, 1], ws.Cells[startRow, startCol]];
						}
                    }
            		break;
            }

            if (lookUpRange != null) {
            	XlSearchOrder order = LookUpSetting == LookUpBy.Col ? XlSearchOrder.xlByColumns : XlSearchOrder.xlByRows;
            	XlSearchDirection direction = SearchDirection == SearchDirection.Previous ? XlSearchDirection.xlPrevious : XlSearchDirection.xlNext;

            	resolvedRange = lookUpRange.Find(LookUpString, System.Type.Missing, XlFindLookIn.xlValues, XlLookAt.xlWhole, order, direction);
            }
        	return resolvedRange;
        }

        #endregion
    }
}
